"""
报警管理服务
负责监控数据异常并发送报警通知
"""

import logging
import threading
import time
from datetime import datetime
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass
from enum import Enum

from core.base_driver import TagValue

class AlarmLevel(Enum):
    """报警级别"""
    INFO = "info"
    WARNING = "warning"
    HIGH = "high"
    CRITICAL = "critical"

class AlarmType(Enum):
    """报警类型"""
    THRESHOLD = "threshold"
    STATE_CHANGE = "state_change"
    COMMUNICATION = "communication"
    SYSTEM = "system"

@dataclass
class AlarmRule:
    """报警规则"""
    device_name: str
    tag_name: str
    alarm_type: AlarmType
    level: AlarmLevel
    enabled: bool = True
    
    # 阈值报警参数
    high_limit: Optional[float] = None
    low_limit: Optional[float] = None
    critical_limit: Optional[float] = None
    
    # 状态变化报警参数
    watch_states: Optional[List[Any]] = None
    
    # 报警消息
    message: str = ""
    
    # 报警抑制时间（秒）
    suppress_time: int = 300

@dataclass
class AlarmEvent:
    """报警事件"""
    id: str
    device_name: str
    tag_name: str
    alarm_type: AlarmType
    level: AlarmLevel
    message: str
    value: Any
    timestamp: datetime
    acknowledged: bool = False
    acknowledged_by: Optional[str] = None
    acknowledged_at: Optional[datetime] = None

class AlarmService:
    """报警管理服务"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.enabled = config.get('enabled', True)
        self.logger = logging.getLogger(self.__class__.__name__)
        
        # 报警规则
        self.alarm_rules: Dict[str, AlarmRule] = {}
        
        # 活动报警
        self.active_alarms: Dict[str, AlarmEvent] = {}
        
        # 报警历史
        self.alarm_history: List[AlarmEvent] = []
        
        # 报警抑制记录
        self.suppressed_alarms: Dict[str, datetime] = {}
        
        # 回调函数
        self.alarm_callbacks: List[Callable[[AlarmEvent], None]] = []
        
        # 线程锁
        self.lock = threading.RLock()
        
        # 通知配置
        self.notification_config = config.get('notification', {})
        
        self.logger.info("报警服务初始化完成")
    
    def add_alarm_rule(self, rule: AlarmRule):
        """添加报警规则"""
        with self.lock:
            rule_key = f"{rule.device_name}.{rule.tag_name}"
            self.alarm_rules[rule_key] = rule
            self.logger.info(f"添加报警规则: {rule_key}")
    
    def remove_alarm_rule(self, device_name: str, tag_name: str):
        """移除报警规则"""
        with self.lock:
            rule_key = f"{device_name}.{tag_name}"
            if rule_key in self.alarm_rules:
                del self.alarm_rules[rule_key]
                self.logger.info(f"移除报警规则: {rule_key}")
    
    def check_alarm(self, tag_value: TagValue):
        """检查单个标签值是否触发报警"""
        if not self.enabled:
            return
        
        rule_key = f"{tag_value.device_name}.{tag_value.tag_name}"
        
        with self.lock:
            if rule_key not in self.alarm_rules:
                return
            
            rule = self.alarm_rules[rule_key]
            if not rule.enabled:
                return
            
            # 检查报警抑制
            if self._is_suppressed(rule_key):
                return
            
            # 根据报警类型检查
            alarm_event = None
            
            if rule.alarm_type == AlarmType.THRESHOLD:
                alarm_event = self._check_threshold_alarm(rule, tag_value)
            elif rule.alarm_type == AlarmType.STATE_CHANGE:
                alarm_event = self._check_state_change_alarm(rule, tag_value)
            elif rule.alarm_type == AlarmType.COMMUNICATION:
                alarm_event = self._check_communication_alarm(rule, tag_value)
            
            if alarm_event:
                self._trigger_alarm(alarm_event)
    
    def _check_threshold_alarm(self, rule: AlarmRule, tag_value: TagValue) -> Optional[AlarmEvent]:
        """检查阈值报警"""
        try:
            value = float(tag_value.value)
        except (ValueError, TypeError):
            return None
        
        alarm_event = None
        
        # 检查严重报警
        if rule.critical_limit is not None and value >= rule.critical_limit:
            alarm_event = AlarmEvent(
                id=f"{rule.device_name}.{rule.tag_name}.critical.{int(time.time())}",
                device_name=rule.device_name,
                tag_name=rule.tag_name,
                alarm_type=rule.alarm_type,
                level=AlarmLevel.CRITICAL,
                message=f"{rule.message or '严重阈值报警'}: 值={value}, 限值={rule.critical_limit}",
                value=value,
                timestamp=tag_value.timestamp
            )
        
        # 检查高限报警
        elif rule.high_limit is not None and value >= rule.high_limit:
            alarm_event = AlarmEvent(
                id=f"{rule.device_name}.{rule.tag_name}.high.{int(time.time())}",
                device_name=rule.device_name,
                tag_name=rule.tag_name,
                alarm_type=rule.alarm_type,
                level=AlarmLevel.HIGH,
                message=f"{rule.message or '高限报警'}: 值={value}, 限值={rule.high_limit}",
                value=value,
                timestamp=tag_value.timestamp
            )
        
        # 检查低限报警
        elif rule.low_limit is not None and value <= rule.low_limit:
            alarm_event = AlarmEvent(
                id=f"{rule.device_name}.{rule.tag_name}.low.{int(time.time())}",
                device_name=rule.device_name,
                tag_name=rule.tag_name,
                alarm_type=rule.alarm_type,
                level=AlarmLevel.WARNING,
                message=f"{rule.message or '低限报警'}: 值={value}, 限值={rule.low_limit}",
                value=value,
                timestamp=tag_value.timestamp
            )
        
        return alarm_event
    
    def _check_state_change_alarm(self, rule: AlarmRule, tag_value: TagValue) -> Optional[AlarmEvent]:
        """检查状态变化报警"""
        if not rule.watch_states:
            return None
        
        if tag_value.value in rule.watch_states:
            return AlarmEvent(
                id=f"{rule.device_name}.{rule.tag_name}.state.{int(time.time())}",
                device_name=rule.device_name,
                tag_name=rule.tag_name,
                alarm_type=rule.alarm_type,
                level=rule.level,
                message=f"{rule.message or '状态变化报警'}: 当前状态={tag_value.value}",
                value=tag_value.value,
                timestamp=tag_value.timestamp
            )
        
        return None
    
    def _check_communication_alarm(self, rule: AlarmRule, tag_value: TagValue) -> Optional[AlarmEvent]:
        """检查通信报警"""
        if tag_value.quality != "GOOD":
            return AlarmEvent(
                id=f"{rule.device_name}.{rule.tag_name}.comm.{int(time.time())}",
                device_name=rule.device_name,
                tag_name=rule.tag_name,
                alarm_type=rule.alarm_type,
                level=AlarmLevel.WARNING,
                message=f"{rule.message or '通信异常'}: 数据质量={tag_value.quality}",
                value=tag_value.value,
                timestamp=tag_value.timestamp
            )
        
        return None
    
    def _is_suppressed(self, rule_key: str) -> bool:
        """检查报警是否被抑制"""
        if rule_key not in self.suppressed_alarms:
            return False
        
        rule = self.alarm_rules[rule_key]
        last_alarm_time = self.suppressed_alarms[rule_key]
        current_time = datetime.now()
        
        time_diff = (current_time - last_alarm_time).total_seconds()
        
        if time_diff < rule.suppress_time:
            return True
        else:
            # 抑制时间已过，移除抑制记录
            del self.suppressed_alarms[rule_key]
            return False
    
    def _trigger_alarm(self, alarm_event: AlarmEvent):
        """触发报警"""
        with self.lock:
            # 添加到活动报警
            self.active_alarms[alarm_event.id] = alarm_event
            
            # 添加到历史记录
            self.alarm_history.append(alarm_event)
            
            # 记录抑制时间
            rule_key = f"{alarm_event.device_name}.{alarm_event.tag_name}"
            self.suppressed_alarms[rule_key] = alarm_event.timestamp
            
            # 限制历史记录长度
            if len(self.alarm_history) > 10000:
                self.alarm_history = self.alarm_history[-5000:]
            
            self.logger.warning(f"触发报警: {alarm_event.message}")
            
            # 调用回调函数
            for callback in self.alarm_callbacks:
                try:
                    callback(alarm_event)
                except Exception as e:
                    self.logger.error(f"报警回调执行失败: {e}")
            
            # 发送通知
            self._send_notification(alarm_event)
    
    def _send_notification(self, alarm_event: AlarmEvent):
        """发送报警通知"""
        # 这里可以实现邮件、短信、Webhook等通知方式
        try:
            # 邮件通知
            email_config = self.notification_config.get('email', {})
            if email_config.get('enabled', False):
                self._send_email_notification(alarm_event, email_config)
            
            # Webhook通知
            webhook_config = self.notification_config.get('webhook', {})
            if webhook_config.get('enabled', False):
                self._send_webhook_notification(alarm_event, webhook_config)
                
        except Exception as e:
            self.logger.error(f"发送报警通知失败: {e}")
    
    def _send_email_notification(self, alarm_event: AlarmEvent, config: Dict[str, Any]):
        """发送邮件通知"""
        # 简单的邮件通知实现
        self.logger.info(f"邮件通知: {alarm_event.message}")
    
    def _send_webhook_notification(self, alarm_event: AlarmEvent, config: Dict[str, Any]):
        """发送Webhook通知"""
        # 简单的Webhook通知实现
        self.logger.info(f"Webhook通知: {alarm_event.message}")
    
    def acknowledge_alarm(self, alarm_id: str, acknowledged_by: str) -> bool:
        """确认报警"""
        with self.lock:
            if alarm_id in self.active_alarms:
                alarm = self.active_alarms[alarm_id]
                alarm.acknowledged = True
                alarm.acknowledged_by = acknowledged_by
                alarm.acknowledged_at = datetime.now()
                
                self.logger.info(f"报警已确认: {alarm_id} by {acknowledged_by}")
                return True
            
            return False
    
    def clear_alarm(self, alarm_id: str) -> bool:
        """清除报警"""
        with self.lock:
            if alarm_id in self.active_alarms:
                del self.active_alarms[alarm_id]
                self.logger.info(f"报警已清除: {alarm_id}")
                return True
            
            return False
    
    def get_active_alarms(self) -> List[AlarmEvent]:
        """获取活动报警"""
        with self.lock:
            return list(self.active_alarms.values())
    
    def get_alarm_history(self, limit: int = 100) -> List[AlarmEvent]:
        """获取报警历史"""
        with self.lock:
            return self.alarm_history[-limit:]
    
    def add_alarm_callback(self, callback: Callable[[AlarmEvent], None]):
        """添加报警回调函数"""
        self.alarm_callbacks.append(callback)
    
    def remove_alarm_callback(self, callback: Callable[[AlarmEvent], None]):
        """移除报警回调函数"""
        if callback in self.alarm_callbacks:
            self.alarm_callbacks.remove(callback)
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取报警统计信息"""
        with self.lock:
            total_rules = len(self.alarm_rules)
            active_alarms = len(self.active_alarms)
            total_history = len(self.alarm_history)
            
            # 按级别统计活动报警
            level_stats = {}
            for alarm in self.active_alarms.values():
                level = alarm.level.value
                level_stats[level] = level_stats.get(level, 0) + 1
            
            return {
                'total_rules': total_rules,
                'active_alarms': active_alarms,
                'total_history': total_history,
                'level_statistics': level_stats,
                'suppressed_count': len(self.suppressed_alarms)
            }
    
    def load_rules_from_config(self, devices_config: List[Dict[str, Any]]):
        """从设备配置加载报警规则"""
        for device_config in devices_config:
            device_name = device_config.get('name')
            points = device_config.get('points', [])
            
            for point in points:
                alarm_config = point.get('alarm')
                if alarm_config and alarm_config.get('enabled', False):
                    try:
                        rule = AlarmRule(
                            device_name=device_name,
                            tag_name=point['name'],
                            alarm_type=AlarmType(alarm_config.get('type', 'threshold')),
                            level=AlarmLevel(alarm_config.get('level', 'warning')),
                            enabled=True,
                            high_limit=alarm_config.get('high'),
                            low_limit=alarm_config.get('low'),
                            critical_limit=alarm_config.get('critical'),
                            message=alarm_config.get('message', ''),
                            suppress_time=alarm_config.get('suppress_time', 300)
                        )
                        
                        self.add_alarm_rule(rule)
                        
                    except Exception as e:
                        self.logger.error(f"加载报警规则失败 {device_name}.{point['name']}: {e}")
    
    def close(self):
        """关闭报警服务"""
        self.logger.info("报警服务已关闭") 